package com.deruan.hotcore.resource.search;

import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.TimeZone;
import java.util.Vector;
import java.util.logging.Logger;

import javax.swing.ImageIcon;

import org.columba.api.gui.frame.IFrameMediator;
import org.columba.core.gui.search.StringCriteriaRenderer;
import org.columba.core.gui.search.api.ICriteriaRenderer;
import org.columba.core.gui.search.api.IResultPanel;
import org.columba.core.search.SearchCriteria;
import org.columba.core.search.api.ISearchCriteria;
import org.columba.core.search.api.ISearchProvider;
import org.columba.core.search.api.ISearchRequest;
import org.columba.core.search.api.ISearchResult;
import org.columba.mail.resourceloader.IconKeys;
import org.columba.mail.resourceloader.MailImageLoader;

import com.deruan.hotcore.base.common.bean.ResourceBean;
import com.deruan.hotcore.resource.model.ResourceModelFactory;
import com.deruan.hotcore.resource.search.gui.ComplexResourceResultPanel;
import com.deruan.hotcore.resource.search.gui.CriteriaResourceResultPanel;

public class ResourceSearchProvider implements ISearchProvider
{
	public static final String CRITERIA_BODY_CONTAINS = "body_contains";

	public static final String CRITERIA_FROM_CONTAINS = "from_contains";
	
	public static final String CRITERIA_SUBJECT_CONTAINS = "subject_contains";
	
	public static final String CRITERIA_TYPE_CONTAINS = "type_contains";

	private static final Logger LOG = Logger
			.getLogger("org.columba.mail.search.MailSearchProvider");
	private List<ResourceBean> lastSearchResources;

	private int totalResultCount = 0;

	private ResourceBundle bundle;

	/**
	 * check if a single criteria search was done. False, if a multiple criteria search was done.
	 */
	private boolean singleCriteriaSearch = false;

	public ResourceSearchProvider() 
	{
		bundle = ResourceBundle.getBundle("org.columba.mail.i18n.search");
	}

	public String getTechnicalName() 
	{
		return "ResourceSearchProvider";
	}

	public String getName() 
	{
		return bundle.getString("resource_title");
	}

	public String getDescription() {
		return bundle.getString("resource_description");
	}

	public ImageIcon getIcon() 
	{
		return MailImageLoader.getSmallIcon(IconKeys.MESSAGE_READ);
	}

	public List<ISearchCriteria> getAllCriteria(String searchTerm) 
	{
		List<ISearchCriteria> list = new Vector<ISearchCriteria>();

		// check if string is a number
		boolean numberFormat = false;
		try {
			int searchTermInt = Integer.parseInt(searchTerm);
			numberFormat = true;
		} catch (NumberFormatException e) {
		}

		if (searchTerm.equals(""))
			numberFormat = true;
		list.add(getCriteria(ResourceSearchProvider.CRITERIA_SUBJECT_CONTAINS,
				searchTerm));
		list.add(getCriteria(ResourceSearchProvider.CRITERIA_FROM_CONTAINS,
				searchTerm));
		list.add(getCriteria(ResourceSearchProvider.CRITERIA_BODY_CONTAINS,
				searchTerm));
		list.add(getCriteria(ResourceSearchProvider.CRITERIA_TYPE_CONTAINS,
				searchTerm));
		return list;
	}

	public IResultPanel getResultPanel(String searchCriteriaTechnicalName) 
	{
		return new CriteriaResourceResultPanel(getTechnicalName(),searchCriteriaTechnicalName);
	}

	public IResultPanel getComplexResultPanel() 
	{
		return new ComplexResourceResultPanel(getTechnicalName());
	}

	public ICriteriaRenderer getCriteriaRenderer(String searchCriteriaTechnicalName) 
	{
		if (searchCriteriaTechnicalName
				.equals(ResourceSearchProvider.CRITERIA_BODY_CONTAINS))
			return new StringCriteriaRenderer(getCriteria(
					ResourceSearchProvider.CRITERIA_BODY_CONTAINS, ""), this);
		else if (searchCriteriaTechnicalName
				.equals(ResourceSearchProvider.CRITERIA_SUBJECT_CONTAINS))
			return new StringCriteriaRenderer(getCriteria(
					ResourceSearchProvider.CRITERIA_SUBJECT_CONTAINS, ""), this);
		else if (searchCriteriaTechnicalName
				.equals(ResourceSearchProvider.CRITERIA_FROM_CONTAINS))
			return new StringCriteriaRenderer(getCriteria(
					ResourceSearchProvider.CRITERIA_FROM_CONTAINS, ""), this);
		else if (searchCriteriaTechnicalName
				.equals(ResourceSearchProvider.CRITERIA_TYPE_CONTAINS))
			return new StringCriteriaRenderer(getCriteria(
					ResourceSearchProvider.CRITERIA_TYPE_CONTAINS, ""), this);
		else
			throw new IllegalArgumentException("no renderer available for <"
					+ searchCriteriaTechnicalName + ">");
	}

	public ISearchCriteria getCriteria(String technicalName, String searchTerm) 
	{
		String title = MessageFormat.format(bundle.getString(technicalName
				+ "_title"), new Object[] { searchTerm });
		String name = bundle.getString(technicalName + "_name");
		String description = MessageFormat.format(bundle
				.getString(technicalName + "_description"),
				new Object[] { searchTerm });

		return new SearchCriteria(technicalName, name, title, description);
	}

	public List<ISearchResult> query(String searchTerm,
			String searchCriteriaTechnicalName, boolean searchInside,
			int startIndex, int resultCount) 
    {
		List<ISearchResult> result = new Vector<ISearchResult>();
		// remove memorized search folders
		if (!searchInside) 
		{
			lastSearchResources = null;
		}
		// return empty result, in case the criteria doesn't match the search
		// term
		if (searchTerm == null)
			return result;
		try 
		{
			if (searchInside) 
			{
				if (lastSearchResources != null) 
				{
					LOG.info("reuse existing virtual folder");
					// create new search folder, but re-use old search folder
					lastSearchResources = ResourceModelFactory.searchResource(searchTerm, searchCriteriaTechnicalName,lastSearchResources);
				} else 
				{
					totalResultCount = 0;
					return result;
				}
			} else 
			{
				LOG.info("create new virtual folder");
				lastSearchResources = ResourceModelFactory.searchResource(searchTerm, searchCriteriaTechnicalName,null);
			}
			// retrieve the actual search result data
			retrieveResultData(result);
			// sort all the results
			Collections.sort(result, new MyComparator());
			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		// memorize total result count
		totalResultCount = result.size();

		singleCriteriaSearch = true;

		return result;
	}

	public List<ISearchResult> query(List<ISearchRequest> list,
			boolean matchAll, boolean searchInside, int startIndex,
			int resultCount) {
		
		Vector<ISearchResult> v = new Vector<ISearchResult>();
		List<ISearchResult> result= null;
		// remove all memorized search folders
		if (!searchInside) {
			lastSearchResources = null;
		}	
		Iterator<ISearchRequest> it = list.iterator();
		while (it.hasNext()) 
		{
			ISearchRequest r = it.next();
			String searchCriteriaTechnicalName = r.getCriteria();
			String searchTerm = r.getSearchTerm();
			result = query(searchTerm, searchCriteriaTechnicalName, searchInside, startIndex, resultCount);
		    
			if(!searchInside)
				 v.addAll(result);
		}
        if(!searchInside)
        {
        	totalResultCount = v.size();
        	return v;
        }
        else {
    		// memorize total result count
    		totalResultCount = result.size();
    		return result;
		}
		//singleCriteriaSearch = false;	
	}

	private void retrieveResultData(List<ISearchResult> resultList) throws Exception 
	{
		Iterator<ResourceSearchResult> iterator = ResourceModelFactory.getResourceSearchResultIterator();
		while(iterator.hasNext())
		{
				/*String title = resourceBean.getTitle();
				String from = resourceBean.getFrom();
				String type = resourceBean.getType();
				Date date = resourceBean.getPublicDate();
				String description = from.toString() + " " + date;
				URI uri = null;
				ImageIcon statusIcon = null;
				//Flags flags = resourceBean.getFlags();
				Flags flags = new Flags();
				if (flags.getDeleted()) 
				{
					statusIcon = ImageLoader.getSmallIcon("user-trash.png");

				} else if (flags.getAnswered()) 
				{
					statusIcon = MailImageLoader
							.getSmallIcon("message-mail-replied.png");
				} else if (flags.getDraft()) 
				{
					statusIcon = MailImageLoader.getSmallIcon("edit.png");
				} else if (!flags.getSeen()) 
				{
					statusIcon = MailImageLoader
							.getSmallIcon("message-mail-unread.png");
				} else if (flags.getSeen()) 
				{
					statusIcon = MailImageLoader
							.getSmallIcon("message-mail-read.png");
				}
				*/
				resultList.add(iterator.next());
		}	
	}

	class DateHelper {
		SimpleDateFormat dfWeek = new SimpleDateFormat("EEE HH:mm", Locale
				.getDefault());

		// use local date settings
		DateFormat dfCommon = DateFormat.getDateInstance();

		static final long OneDay = 24 * 60 * 60 * 1000;

		TimeZone localTimeZone = TimeZone.getDefault();

		private int getLocalDaysDiff(long t) {
			return (int) (((System.currentTimeMillis() + localTimeZone
					.getRawOffset()) - (((t + localTimeZone.getRawOffset()) / OneDay) * OneDay)) / OneDay);
		}

		public String format(Date date) {
			String dateString = null;

			int diff = getLocalDaysDiff(date.getTime());

			// if ( today
			if ((diff >= 0) && (diff < 7)) {
				dateString = dfWeek.format(date);
			} else {
				dateString = dfCommon.format(date);
			}
			return dateString;
		}

	}

	public int getTotalResultCount() {
		return totalResultCount;
	}

	public void showAllResults(IFrameMediator mediator, String searchTerm,
			String searchCriteriaTechnicalName) 
	{
	}

	/**
	 * Comparator for message result. Sortes results by Date. More recent
	 * results are shown first.
	 *
	 * @author frd
	 */
	class MyComparator implements Comparator {
		MyComparator() {
		}

		public int compare(Object o1, Object o2) {
			ResourceSearchResult result = (ResourceSearchResult) o1;
			ResourceSearchResult result2 = (ResourceSearchResult) o2;

			int num1 = result.getResultNum();
			int num2 = result2.getResultNum();

			if (num1 == 0 && num2 == 0)
				return 0;
			if (num1 != 0 && num2 == 0)
				return -1;
			if (num1 == 0 && num2 != 0)
				return 1;

			return -(Integer.valueOf(num1)).compareTo(Integer.valueOf(num2));
		}

	}

	public ISearchCriteria getDefaultCriteria(String searchTerm) {
		return getCriteria(ResourceSearchProvider.CRITERIA_SUBJECT_CONTAINS, searchTerm);
	}

	public boolean hasSingleCriteriaSearchResult() {
		return singleCriteriaSearch && lastSearchResources!= null;
	}
}
